package repository.impl;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import repository.UserRepository;

import command.SearchForm;

import domain.User;
import domain.exceptions.DuplicateException;
import domain.exceptions.DuplicateException.DupErrorCode;


@Repository
public class UserRepositoryImpl extends AbstractHibernateRepository<User> implements UserRepository {

	private static String USER = "u.";
	private static String PROFILE = USER + "profile.";
	private static String LINKEDIN = PROFILE + "linkedInProfile.";
	private static String FACEBOOK = PROFILE + "facebookProfile.";
	
	@Autowired
	public UserRepositoryImpl(SessionFactory sessionfactory){
		super(sessionfactory);
	}
	
	@Override
	public User validate(String docnumber, String password) {
		String hql = "FROM User WHERE docnumber=? AND password=?";
		List<User> result = find(hql, docnumber, password);
		return result.isEmpty() ? null : result.get(0);
	}

	@Override
	public User getUser(int id) {
		return get(User.class, id);
	}
	
	@Override
	public User getUserByDocNumber(String docnumber) {
		String hql = "FROM User WHERE docnumber=?";
		List<User> result = find(hql, docnumber);
		return result.isEmpty() ? null : result.get(0);
	}
	
	@Override
	public User getUserByEmail(String email) {
		String hql = "FROM User WHERE email=?";
		List<User> result = find(hql, email);
		return result.isEmpty() ? null : result.get(0);
	}
	
	@Override
	public User getUser(String docnumber, String email) {
		String hql = "FROM User WHERE docnumber=? AND email=?";
		List<User> result = find(hql, docnumber, email);
		return result.isEmpty() ? null : result.get(0);
	}
	
	@Override
	public void newUser(User user)throws DuplicateException{
		if (getUserByDocNumber(user.getDocNumber()) != null) {
			throw new DuplicateException(DupErrorCode.DUP_DOC_NUMBER);
		} else if (getUserByEmail(user.getEmail()) != null) {
			throw new DuplicateException(DupErrorCode.DUP_EMAIL);
		}
		save(user);
	}

	@Override
	public List<User> getRegisteredUsers() {
		String hql = "FROM User WHERE admin=0 and active=1 ORDER BY lastaccess DESC";
		return find(hql);		
	}
	
	@Override
	public List<User> getAdminUsers() {
		String hql = "FROM User WHERE admin=1 ORDER BY lastaccess DESC";
		return find(hql);		
	}
	
	@Override
	public void deleteUser(User user){
		delete(user);
	}

	@Override
	public List<User> getPendingUserRequests() {
		String hql = "FROM User WHERE admin=0 and active=1 and confirmed=0";
		return find(hql);
	}
	
	@Override
	public List<User> search(SearchForm searchForm) {
		String hql = "FROM User as u WHERE admin=0 and active=1 AND (" + USER + "name LIKE ? OR " + getQueryParam(LINKEDIN + "firstName") + ")" +
				" AND (" + USER + "email LIKE ? OR " + getQueryParam(PROFILE + "emails") + ")" +
				" AND (" + getQueryParam(USER + "lastname") + " OR " + getQueryParam(LINKEDIN + "lastName") + ")" +
				" AND " + USER + "docnumber LIKE ?" +
				" AND (" + getQueryParam(PROFILE + "education") + " OR " + getQueryParam(LINKEDIN + "educations") + ")" +
				" AND (" + getQueryParam(PROFILE + "title") + " OR " + getQueryParam(LINKEDIN + "educations") + ")" +
				" AND (" + getQueryParam(PROFILE + "actualjob") + " OR " + getQueryParam(LINKEDIN + "threeCurrentPositions") + " OR " + getQueryParam(LINKEDIN + "threePastPositions") + ")";
		List<String> parameters = new ArrayList<String>();
		parameters.add("%" + searchForm.getName() + "%");
		parameters.add("%" + searchForm.getName() + "%");
		parameters.add("%" + searchForm.getEmail() + "%");
		parameters.add("%" + searchForm.getEmail() + "%");
		parameters.add("%" + searchForm.getLastname() + "%");
		parameters.add("%" + searchForm.getLastname() + "%");
		parameters.add("%" + searchForm.getDocnumber() + "%");
		parameters.add("%" + searchForm.getEducation() + "%");
		parameters.add("%" + searchForm.getEducation() + "%");
		parameters.add("%" + searchForm.getTitle() + "%");
		parameters.add("%" + searchForm.getTitle() + "%");
		parameters.add("%" + searchForm.getJob() + "%");
		parameters.add("%" + searchForm.getJob() + "%");
		parameters.add("%" + searchForm.getJob() + "%");
		String[] keywordFields = {USER + "docnumber", USER + "email", USER + "lastname", USER + "name", PROFILE + "experience", PROFILE + "education", 
				PROFILE + "recommendations", PROFILE + "title", PROFILE + "actualjob", PROFILE + "extract", 
				PROFILE + "interests", PROFILE + "knowldege"};
		hql += " AND (";
		hql += addKeywordFields(keywordFields, parameters, searchForm.getKeywords());
		if (searchForm.searchLinkedin()) {
			String[] keywordFieldsExtended = {LINKEDIN + "certifications", LINKEDIN + "educations", 
					LINKEDIN + "firstName", LINKEDIN + "headline", LINKEDIN + "honors", LINKEDIN + "industry", 
					LINKEDIN + "interests", LINKEDIN + "languages", LINKEDIN + "lastName", LINKEDIN + "locations", 
					LINKEDIN + "mainAddress", LINKEDIN + "positions", LINKEDIN + "publications", 
					LINKEDIN + "recommendationsReceived", LINKEDIN + "skills", LINKEDIN + "specialties", 
					LINKEDIN + "summary", LINKEDIN + "threeCurrentPositions", LINKEDIN + "threePastPositions"};
			hql += " OR ";
			hql += addKeywordFields(keywordFieldsExtended, parameters, searchForm.getKeywords());
		}
//		if (searchForm.searchFacebook()) {
////			String[] keywordFieldsExtended = {FACEBOOK + "blabla"};
//			String[] keywordFieldsExtended = {};
//			hql += " OR ";
//			hql += addKeywordFields(keywordFieldsExtended, parameters, searchForm.getKeywords());
//		}
		hql += ")";
		List<User> result = find(hql, parameters);
 		return result;	
	}

	@Override
	public List<User> getRegularConfirmedUsers() {
		String hql = "FROM User where admin = ? and active=1 and confirmed = ?";
		List<User> result = find(hql, false, true);
		return result.isEmpty() ? null : result;
	}

	private String getQueryParam(String param) {
		return "COALESCE(" + param + ", '') LIKE ?";
	}

	private String addKeywordFields(String[] keywordFields, List<String> parameters, String keywords) {
		String hql = "";
		String[] keywordSplit = keywords.split(" ");
		int k = 0;
		for (String key: keywordSplit) {
			hql += (k++ > 0 ? " OR (" : "(");
			//for each field included in "keywords"
			for (int i = 0; i<keywordFields.length; i++) {
				hql += getQueryParam(keywordFields[i]) + ((i == keywordFields.length-1) ? "": " OR ");
				parameters.add("%" + key + "%");
			}
			hql += ")";
		}
		return hql;
	}

	@Override
	public List<User> searchByName(String name) {
		List<String> parameters = new ArrayList<String>();
		String hql = "FROM User as u WHERE u.admin=0 AND u.active=1 AND u.confirmed = 1 AND ";
		String[] nameSplit = name.split(" ");
		int i = 0;
		for (String nameKey: nameSplit) {
			hql += (i++ > 0 ? " AND (" : "(");
			hql += USER + "name LIKE ? OR " + USER + "lastname LIKE ?";
			parameters.add("%" + nameKey + "%");
			parameters.add("%" + nameKey + "%");
			hql += ")";
		}
		List<User> result = find(hql, parameters);
		return result;
	}

	@Override
	public User getAdminUserWithSocialToken() {
		String hql = "FROM User u WHERE u.admin=? and u.socialtoken.linkedintoken is not null and u.socialtoken.facebooktoken is not null";
		List<User> result = find(hql, true);
		return result.isEmpty() ? null : result.get(0);
	}

	@Override
	public void updateUser(User user) {
		if (user != null) {
			update(user);
		}
	}
	
}